﻿using System;
using System.Reflection;

using Gurucore.Framework.Core.Proxy;
using Gurucore.Framework.DataAccess;

namespace #class.Namespace#
{
	public class #class.Name#_Proxy : #class.Name#
	{
		<ad:foreach collection="#constructors#" var="constructor">
		public #constructor.Name#_Proxy(#constructor.ParamsDecl#)
			: base(#constructor.Params#)
		{
		}
		</ad:foreach>

		<ad:foreach collection="#methods#" var="method">
		public override <ad:if test="#method.IsVoidMethod#"> void <ad:else> #method.ReturnType# </ad:if> #method.Name#(#method.ParamsDecl#)
		{
			<ad:if test="#not(method.IsVoidMethod)#">
			#method.ReturnType# result;
			</ad:if>			
			
			MethodInfo oMethod = this.GetType().GetMethod("#method.Name#");
						
			<ad:if test="#method.IsWrapped#">
			#method.CallWrapperClass# oCallWrapperInterceptor = new #method.CallWrapperClass#();
			<ad:if test="#method.IsVoidMethod#">
			<ad:if test="#equals(method.Params,"")#">
			oCallWrapperInterceptor.Intercept(this, oMethod, InterceptorType.CallWrapper);
			<ad:else>
			oCallWrapperInterceptor.Intercept(this, oMethod, InterceptorType.CallWrapper, #method.Params#);
			</ad:if>
			<ad:else>
			<ad:if test="#equals(method.Params,"")#">
			result = (#method.ReturnType#)oCallWrapperInterceptor.Intercept(this, oMethod, InterceptorType.CallWrapper);
			<ad:else>
			result = (#method.ReturnType#)oCallWrapperInterceptor.Intercept(this, oMethod, InterceptorType.CallWrapper, #method.Params#);
			</ad:if>
			</ad:if>
			<ad:else>
			try
			{
				<ad:foreach collection="#method.BeforeCallingInterceptors#" var="interceptor" index="i">
				#interceptor.Class# oBeforeCallingInterceptor#i# = new #interceptor.Class#();
				<ad:if test="#equals(method.Params,"")#">
				oBeforeCallingInterceptor#i#.Intercept(this, oMethod, InterceptorType.BeforeCalling);
				<ad:else>
				oBeforeCallingInterceptor#i#.Intercept(this, oMethod, InterceptorType.BeforeCalling, #method.Params#);
				</ad:if>			
				</ad:foreach>
		
				<ad:if test="#method.IsVoidMethod#">
				base.#method.Name#(#method.Params#);
				<ad:else>
				result = base.#method.Name#(#method.Params#);
				</ad:if>

				<ad:foreach collection="#method.AfterCallSuccessInterceptors#" var="interceptor" index="i">
				#interceptor.Class# oAfterCallSuccessInterceptor#i# = new #interceptor.Class#();
				<ad:if test="#equals(method.Params,"")#">
				oAfterCallSuccessInterceptor#i#.Intercept(this, oMethod, InterceptorType.BeforeCalling);
				<ad:else>
				oAfterCallSuccessInterceptor#i#.Intercept(this, oMethod, InterceptorType.BeforeCalling, #method.Params#);
				</ad:if>			
				</ad:foreach>		
			}
			catch (Exception ex)
			{
				<ad:foreach collection="#method.AfterCallFailureInterceptors#" var="interceptor" index="i">
				#interceptor.Class# oAfterCallFailureInterceptor#i# = new #interceptor.Class#();
				<ad:if test="#equals(method.Params,"")#">
				oAfterCallFailureInterceptor#i#.Intercept(this, oMethod, InterceptorType.AfterCallFailure);
				<ad:else>
				oAfterCallFailureInterceptor#i#.Intercept(this, oMethod, InterceptorType.AfterCallFailure, #method.Params#);
				</ad:if>			
				</ad:foreach>
		
				throw ex;
			}
			finally
			{
				<ad:foreach collection="#method.AfterReturnedInterceptors#" var="interceptor" index="i">
				#interceptor.Class# oAfterReturnedInterceptor#i# = new #interceptor.Class#();
				<ad:if test="#equals(method.Params,"")#">
				oAfterReturnedInterceptor#i#.Intercept(this, oMethod, InterceptorType.AfterReturned);
				<ad:else>
				oAfterReturnedInterceptor#i#.Intercept(this, oMethod, InterceptorType.AfterReturned, #method.Params#);
				</ad:if>			
				</ad:foreach>		
			}
			</ad:if>			
			
			<ad:if test="#not(method.IsVoidMethod)#">
			return result;
			</ad:if>
		}
		</ad:foreach>

		<ad:foreach collection="#properties#" var="property">
		public override #property.PropertyType# #property.Name#
		{
			<ad:if test="#property.GetterIntercepted#">
			get
			{
				MethodInfo oMethod = this.GetType().GetMethod("get_#property.Name#");
				#property.PropertyType# result;
				try
				{
					<ad:foreach collection="#property.GetterBeforeCallingInterceptors#" var="interceptor" index="i">
					#interceptor.Class# oGetterBeforeCallingInterceptor#i# = new #interceptor.Class#();
					oGetterBeforeCallingInterceptor#i#.Intercept(this, oMethod, InterceptorType.BeforeCalling);
					</ad:foreach>
					result = base.#property.Name#;
					<ad:foreach collection="#property.GetterAfterCallSuccessInterceptors#" var="interceptor" index="i">
					#interceptor.Class# oGetterAfterCallSuccessInterceptor#i# = new #interceptor.Class#();
					oGetterAfterCallSuccessInterceptor#i#.Intercept(this, oMethod, InterceptorType.AfterCallSuccess);
					</ad:foreach>
				}
				catch (Exception ex)
				{
					<ad:foreach collection="#property.GetterAfterCallFailureInterceptors#" var="interceptor" index="i">
					#interceptor.Class# oGetterAfterCallFailureInterceptor#i# = new #interceptor.Class#();
					oGetterAfterCallFailureInterceptor#i#.Intercept(this, oMethod, InterceptorType.AfterCallFailure);
					</ad:foreach>
					throw ex;
				}
				finally
				{
					<ad:foreach collection="#property.GetterAfterReturnedInterceptors#" var="interceptor" index="i">
					#interceptor.Class# oGetterAfterReturnedInterceptor#i# = new #interceptor.Class#();
					oGetterAfterReturnedInterceptor#i#.Intercept(this, oMethod, InterceptorType.AfterReturned);
					</ad:foreach>
				}
				
				return result;
			}
			</ad:if>
			<ad:if test="#property.SetterIntercepted#">
			set
			{
				MethodInfo oMethod = this.GetType().GetMethod("set_#property.Name#");
				try
				{
					<ad:foreach collection="#property.SetterBeforeCallingInterceptors#" var="interceptor" index="i">
					#interceptor.Class# oSetterBeforeCallingInterceptor#i# = new #interceptor.Class#();
					oSetterBeforeCallingInterceptor#i#.Intercept(this, oMethod, InterceptorType.BeforeCalling);
					</ad:foreach>
					base.#property.Name# = value;
					<ad:foreach collection="#property.SetterAfterCallSuccessInterceptors#" var="interceptor" index="i">
					#interceptor.Class# oSetterAfterCallSuccessInterceptor#i# = new #interceptor.Class#();
					oSetterAfterCallSuccessInterceptor#i#.Intercept(this, oMethod, InterceptorType.AfterCallSuccess);
					</ad:foreach>
				}
				catch (Exception ex)
				{
					<ad:foreach collection="#property.SetterAfterCallFailureInterceptors#" var="interceptor" index="i">
					#interceptor.Class# oSetterAfterCallFailureInterceptor#i# = new #interceptor.Class#();
					oSetterAfterCallFailureInterceptor#i#.Intercept(this, oMethod, InterceptorType.AfterCallFailure);
					</ad:foreach>
					throw ex;
				}
				finally
				{
					<ad:foreach collection="#property.SetterAfterReturnedInterceptors#" var="interceptor" index="i">
					#interceptor.Class# oSetterAfterReturnedInterceptor#i# = new #interceptor.Class#();
					oSetterAfterReturnedInterceptor#i#.Intercept(this, oMethod, InterceptorType.AfterReturned);
					</ad:foreach>
				}
			}
			</ad:if>
		}
		</ad:foreach>
	}
}
